package com.amethyst.mybatisplus.config;

import com.amethyst.mybatisplus.constants.Global;
import com.amethyst.mybatisplus.util.LoginUserUtils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.TreeSet;

/**
 * @author Amethyst
 * @date 2021/11/4
 */
@Configuration
public class MybatisPlusConfig {

    @Value("${system.tenant.ignore:null}")
    private TreeSet<String> ignoredTenantTables;

    public static ThreadLocal<String> myTableName = new ThreadLocal<>();

    /**
     * 新版mp，新版的类，名称中带有Inner
     * @return MybatisPlusInterceptor
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        /*动态表名拦截器配置*/
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
//        HashMap<String, TableNameHandler> map = new HashMap<>();
        // 对mp_user表，进行动态表名设置
//        map.put("mp_user", (sql, tableName) -> {
//            return myTableName.get();
//        });
        dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
            String name = myTableName.get();
            // 去除ThreadLocal的值，避免线程复用问题
            myTableName.set(null);
            return name;
        });
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);

        /*多租户配置*/
        /* 若使用了分页插件，需要注意，应先 add TenantLineInnerInterceptor，然后再 add PaginationInnerInterceptor
        * 最后，旧版本的mp还需要设置 MybatisConfiguration#userDeprecatedExecutor = false 避免缓存万一出现问题*/
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
            /**
             * 返回租户id的值，一般是从当前上下文中取出一个租户id，这里写死一个固定值=1
             * @return Expression
             */
            @Override
            public Expression getTenantId() {
                return new LongValue(LoginUserUtils.getTenantId());
            }

            /**
             * 返回表中的表示租户id的列名
             * @return String
             */
            @Override
            public String getTenantIdColumn() {
                return Global.TENANT_ID_COLUMN;
            }

            /**
             * 这是default方法，默认返回false，表示所有表都需要拼接多租户条件
             *
             * @param tableName tableName
             * @return boolean
             */
            @Override
            public boolean ignoreTable(String tableName) {
                // 第一种方法：适合只有一张表需要多租户判断（表名不为 mp_multi_tenant_user 的表，不拼接多租户条件）
                return !"mp_multi_tenant_user".equals(tableName);

                // 第二种方法：当有很多表不需要进行租户id判断时，将不需要判断的表放在配置文件中
//                return ignoredTenantTables.contains(tableName);
            }
        }));

        /*分页插件设置*/
        /*旧版mp 用 PaginationInterceptor*/
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        /*乐观锁设置*/
        /*旧版mp 使用的是OptimisticLockerInterceptor*/
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

    // mybatis-plus 3.4.3.4已经移除此选项
//    @Bean
//    public ConfigurationCustomizer configurationCustomizer() {
//        return configuration -> configuration.setUseDeprecatedExecutor(false);
//    }
}
